#include "XMLManager.h"
#include "ConvTools.h"

#include <iostream>

bool XMLManager::openFile(std::string inFilename, bool inEraseFile)
{
	mXMLDocument.SetValue(inFilename.c_str());
	bool lLoadOkay = mXMLDocument.LoadFile();
	if(lLoadOkay && inEraseFile)
		mXMLDocument.Clear();//Oh yeah, that's how I roll
	return mXMLDocument.SaveFile();
}

bool XMLManager::init(unsigned int inNbFrame)
{
	//TODO::Check if a file is open (return false if not)

	mRootNode = mXMLDocument.RootElement();
	if(!mRootNode)
	{	//inDoc is totally empty. Create a <DAT> Tag
		char* lTextIni = 
			"<?xml version=\"1.0\" standalone=\"no\" ?>"
			"<DAT>"
			"<!--  DoT means Detected or Tracked. It's reserved for the flag [...]  -->"
			"</DAT>";
		mXMLDocument.Parse(lTextIni);
		mRootNode = mXMLDocument.RootElement();

		//Need to fill it
		for(unsigned int i=0;i<inNbFrame;i++)
		{
			TiXmlElement lFrameElement( "Frame" );
			lFrameElement.SetAttribute( "value", i );

			mRootNode->InsertEndChild(lFrameElement);
		}
		mXMLDocument.SaveFile();
	}
	
	mCurrentFrameNode = mRootNode->FirstChildElement();	//Could be null
	//std::cout<<mCurrentFrameNode->Attribute("value");
	mCurrentFrame = 0;
	return true;
}

bool XMLManager::saveFrame(const std::list<Tracker*>& inUpdatedTrackers, int inFrame, bool inEraseFrame)
{
	if(!mRootNode) return false;
	if(!mCurrentFrameNode) return false;
	if(inFrame<mCurrentFrame)
	{
		while(conv2Num<unsigned int>(mCurrentFrameNode->Attribute("value"))!=inFrame)
		{	
			//Exactly like NextSiblingElement() but PreviousSiblingElement() doesnt exist
			TiXmlNode* lNode;
			for (lNode = mCurrentFrameNode->PreviousSibling(); lNode; lNode = lNode->PreviousSibling())
				if (lNode->ToElement())
					break;//mCurrentFrameNode = lNode->ToElement;
			mCurrentFrameNode = lNode->ToElement();
			if(!mCurrentFrameNode)
				return false;
		}
	}
	else if(inFrame>mCurrentFrame)
	{
		while(conv2Num<unsigned int>(mCurrentFrameNode->Attribute("value"))!=inFrame)
		{
			mCurrentFrameNode = mCurrentFrameNode->NextSiblingElement();
			if(!mCurrentFrameNode)
				return false;	
		}
	}
	mCurrentFrame = inFrame;
	return saveFrame(inUpdatedTrackers,inEraseFrame);
}

bool XMLManager::saveFrame(const std::list<Tracker*>& inUpdatedTrackers, bool inEraseFrame)
{
	if(!mCurrentFrameNode) return false;
	
	if(inEraseFrame)
	{
		mCurrentFrameNode->Clear();
	}

	//All object ("confirmed" alive or not ?) still tracked
	for(list<Tracker*>::const_iterator lIter=inUpdatedTrackers.begin();lIter!=inUpdatedTrackers.end();lIter++)
	{
		//Found
		TiXmlElement lDATObjectElement( "DATObject" );
		lDATObjectElement.SetAttribute( "ID",(*lIter)->getID());

		TiXmlElement lPositionElement( "Position" );
		lPositionElement.SetAttribute("x",(*lIter)->getLastSeenDATObject()->mLastPosition.x);
		lPositionElement.SetAttribute("y",(*lIter)->getLastSeenDATObject()->mLastPosition.y);

		TiXmlElement lSizeElement( "Size" );
		lSizeElement.SetAttribute("height",(*lIter)->getLastSeenDATObject()->mLastPosition.height);
		lSizeElement.SetAttribute("width",(*lIter)->getLastSeenDATObject()->mLastPosition.width);

		//DoT
		/*
		enum DoT	//Detected or tracked (usefull in Tracker and for the DATReader, etc.)
		{
			DeadAllAlong = -1,
			Nothing = 0,
			Detected = 1,
			Tracked = 2,
			DetectedAndTracked = 3,
			GroundTruth = 4
		};
		*/
		TiXmlElement lDoTElement( "DoT" );
		if((*lIter)->getLastSeenDATObject()->mLastObjectType.empty())
			lDoTElement.SetAttribute("type",0);
		if((*lIter)->getLastSeenDATObject()->mLastWasDetected && (*lIter)->getLastSeenDATObject()->mHistory.mObjectType.empty())	//No history == Detected ONLY
			lDoTElement.SetAttribute("type",1);
		if(!(*lIter)->getLastSeenDATObject()->mLastWasDetected && !(*lIter)->getLastSeenDATObject()->mHistory.mObjectType.empty())	//History but not detected
			lDoTElement.SetAttribute("type",2);
		if((*lIter)->getLastSeenDATObject()->mLastWasDetected && !(*lIter)->getLastSeenDATObject()->mHistory.mObjectType.empty())	//History and detected
			lDoTElement.SetAttribute("type",3);

		TiXmlElement lLastDetectionElement( "LastDetection" );
		if(!(*lIter)->getLastSeenDATObject()->mLastObjectType.empty())
		{
			lLastDetectionElement.SetAttribute("object",(*lIter)->getLastSeenDATObject()->mLastObjectType.c_str());
			lLastDetectionElement.SetAttribute("frame", mCurrentFrame);
		}
		else
		{
			string lLastObjectType = "";
			int lFramePos = -1;
			if((*lIter)->getLastSeenDATObject()->mHistory.mObjectType.size()!=0)
			{
				for(unsigned int i = (*lIter)->getLastSeenDATObject()->mHistory.mObjectType.size()-1;i>=0;i--)
				{
					lLastObjectType = (*lIter)->getLastSeenDATObject()->mHistory.mObjectType[i];
					if(!lLastObjectType.empty())
					{
						lFramePos = (*lIter)->getLastSeenDATObject()->mHistory.mFrameMapping[i];
						break;
					}
				}
			}
			lLastDetectionElement.SetAttribute("object",lLastObjectType.c_str());
			lLastDetectionElement.SetAttribute("frame",lFramePos);
		}
		lLastDetectionElement.SetDoubleAttribute("generalConfidence",(*lIter)->getLastSeenDATObject()->mGeneralConfidence);
		lLastDetectionElement.SetDoubleAttribute("confidence",(*lIter)->getLastSeenDATObject()->mLastConfidence);	//last confidence


		lDATObjectElement.InsertEndChild(lPositionElement);
		lDATObjectElement.InsertEndChild(lSizeElement);
		lDATObjectElement.InsertEndChild(lDoTElement);
		lDATObjectElement.InsertEndChild(lLastDetectionElement);

		mCurrentFrameNode->InsertEndChild(lDATObjectElement);
	}

	if(!mXMLDocument.SaveFile())
		return false;
	
	//MUST KNOW THAT
	mCurrentFrameNode = mCurrentFrameNode->NextSiblingElement();
	mCurrentFrame++;
	return true;
}

bool XMLManager::saveFrame(const list<DATObject*>& inObjects, int inFrame, bool inEraseFrame, bool inGroundTruth)
{
	if(!mRootNode) return false;
	if(inFrame<mCurrentFrame)
	{
		while(conv2Num<unsigned int>(mCurrentFrameNode->Attribute("value"))!=inFrame)
		{	
			//Exactly like NextSiblingElement() but PreviousSiblingElement() doesnt exist
			TiXmlNode* lNode;
			for (lNode = mCurrentFrameNode->PreviousSibling(); lNode; lNode = lNode->PreviousSibling())
				if (lNode->ToElement())
					break;//mCurrentFrameNode = lNode->ToElement;
			mCurrentFrameNode = lNode->ToElement();
			if(!mCurrentFrameNode)
				return false;
		}
	}
	else if(inFrame>mCurrentFrame)
	{
		while(conv2Num<unsigned int>(mCurrentFrameNode->Attribute("value"))!=inFrame)
		{
			mCurrentFrameNode = mCurrentFrameNode->NextSiblingElement();
			if(!mCurrentFrameNode)
				return false;	
		}
	}
	//else inFrame == mCurrentFrame (nothing to change)
	mCurrentFrame = inFrame;
	return saveFrame(inObjects,inEraseFrame,inGroundTruth);
}

bool XMLManager::saveFrame(const list<DATObject*>& inObjects, bool inEraseFrame, bool inGroundTruth)
{
	if(!mCurrentFrameNode) return false;
	
	if(inEraseFrame)
	{
		mCurrentFrameNode->Clear();
	}

	//All object ("confirmed" alive or not ?) still tracked
	for(list<DATObject*>::const_iterator lIter=inObjects.begin();lIter!=inObjects.end();lIter++)
	{
		//Found
		TiXmlElement lDATObjectElement( "DATObject" );
		lDATObjectElement.SetAttribute( "ID",(*lIter)->mID);

		TiXmlElement lPositionElement( "Position" );
		lPositionElement.SetAttribute("x",(*lIter)->mLastPosition.x);
		lPositionElement.SetAttribute("y",(*lIter)->mLastPosition.y);

		TiXmlElement lSizeElement( "Size" );
		lSizeElement.SetAttribute("height",(*lIter)->mLastPosition.height);
		lSizeElement.SetAttribute("width",(*lIter)->mLastPosition.width);

		TiXmlElement lDoTElement( "DoT" );
		if(inGroundTruth)
			lDoTElement.SetAttribute("type",GROUNDTRUTH);		//Groundtruth
		else
			lDoTElement.SetAttribute("type",DETECTION);		//Detection

		TiXmlElement lLastDetectionElement( "LastDetection" );

		lLastDetectionElement.SetAttribute("object",(*lIter)->mLastObjectType.c_str());
		lLastDetectionElement.SetAttribute("frame", mCurrentFrame);
		lLastDetectionElement.SetDoubleAttribute("generalConfidence",(*lIter)->mGeneralConfidence);
		lLastDetectionElement.SetDoubleAttribute("confidence",(*lIter)->mLastConfidence);	//last confidence

		lDATObjectElement.InsertEndChild(lPositionElement);
		lDATObjectElement.InsertEndChild(lSizeElement);
		lDATObjectElement.InsertEndChild(lDoTElement);
		lDATObjectElement.InsertEndChild(lLastDetectionElement);

		mCurrentFrameNode->InsertEndChild(lDATObjectElement);
	}

	if(!mXMLDocument.SaveFile())
		return false;
	
	//MUST KNOW THAT
	mCurrentFrameNode = mCurrentFrameNode->NextSiblingElement();
	mCurrentFrame++;
	return true;
}

bool XMLManager::changeAttributeValue(int inObjectID, int inFrame,std::string inElementName, std::string inAttribute,std::string inValue)
{
	if(!mRootNode) return false;
	if(!mCurrentFrameNode)
	{
		mCurrentFrameNode = mRootNode->FirstChildElement();	//Could be null
		//std::cout<<mCurrentFrameNode->Attribute("value");
		mCurrentFrame = 0;
	}
		
	if(inFrame<mCurrentFrame)
	{
		while(conv2Num<unsigned int>(mCurrentFrameNode->Attribute("value"))!=inFrame)
		{	
			//Exactly like NextSiblingElement() but PreviousSiblingElement() doesnt exist
			TiXmlNode* lNode;
			for (lNode = mCurrentFrameNode->PreviousSibling(); lNode; lNode = lNode->PreviousSibling())
				if (lNode->ToElement())
					break;//mCurrentFrameNode = lNode->ToElement;
			mCurrentFrameNode = lNode->ToElement();
			if(!mCurrentFrameNode)
				return false;
		}
	}
	else if(inFrame>mCurrentFrame)
	{
		while(conv2Num<unsigned int>(mCurrentFrameNode->Attribute("value"))!=inFrame)
		{
			mCurrentFrameNode = mCurrentFrameNode->NextSiblingElement();
			if(!mCurrentFrameNode)
				return false;	
		}
	}
	mCurrentFrame = inFrame;
	TiXmlElement* lObjectNode = mCurrentFrameNode->FirstChildElement();
	while(conv2Num<unsigned int>(lObjectNode->Attribute("ID"))!=inObjectID)
	{
		lObjectNode = lObjectNode->NextSiblingElement();
		if(!lObjectNode)
			return false;	
	}
	//Good object, at the good frame
	TiXmlElement* lElementNode = lObjectNode->FirstChildElement(inElementName.c_str());
	if(!lElementNode)	//Check if the element exist
		return false;
	if(!(bool)lElementNode->Attribute(inAttribute.c_str()))	//Check if the attribute exist
		return false;
	lElementNode->SetAttribute(inAttribute.c_str(),inValue.c_str());

	if(!mXMLDocument.SaveFile())
		return false;
	//MUST KNOW THAT
	mCurrentFrameNode = mCurrentFrameNode->NextSiblingElement();
	mCurrentFrame++;

	return true;
}

bool XMLManager::changeIDValue(int inObjectToChangeID, int inNewObjectID, int inFrame)
{
	if(!mRootNode) return false;
	if(!mCurrentFrameNode)
	{
		mCurrentFrameNode = mRootNode->FirstChildElement();	//Could be null
		//std::cout<<mCurrentFrameNode->Attribute("value");
		mCurrentFrame = 0;
	}
		
	if(inFrame<mCurrentFrame)
	{
		while(conv2Num<unsigned int>(mCurrentFrameNode->Attribute("value"))!=inFrame)
		{	
			//Exactly like NextSiblingElement() but PreviousSiblingElement() doesnt exist
			TiXmlNode* lNode;
			for (lNode = mCurrentFrameNode->PreviousSibling(); lNode; lNode = lNode->PreviousSibling())
				if (lNode->ToElement())
					break;//mCurrentFrameNode = lNode->ToElement;
			mCurrentFrameNode = lNode->ToElement();
			if(!mCurrentFrameNode)
				return false;
		}
	}
	else if(inFrame>mCurrentFrame)
	{
		while(conv2Num<unsigned int>(mCurrentFrameNode->Attribute("value"))!=inFrame)
		{
			mCurrentFrameNode = mCurrentFrameNode->NextSiblingElement();
			if(!mCurrentFrameNode)
				return false;	
		}
	}
	mCurrentFrame = inFrame;
	TiXmlElement* lObjectNode = mCurrentFrameNode->FirstChildElement();
	while(conv2Num<unsigned int>(lObjectNode->Attribute("ID"))!=inObjectToChangeID)
	{
		lObjectNode = lObjectNode->NextSiblingElement();
		if(!lObjectNode)
			return false;	
	}
	//Good object, at the good frame
	lObjectNode->SetAttribute("ID",conv2Str<int>(inNewObjectID).c_str());

	if(!mXMLDocument.SaveFile())
		return false;
	//MUST KNOW THAT
	mCurrentFrameNode = mCurrentFrameNode->NextSiblingElement();
	mCurrentFrame++;

	return true;
}

bool XMLManager::changeFrameAttributeValue(int inFrame,std::string inValue)
{
	if(!mRootNode) return false;
	if(inFrame<mCurrentFrame)
	{
		while(conv2Num<unsigned int>(mCurrentFrameNode->Attribute("value"))!=inFrame)
		{	
			//Exactly like NextSiblingElement() but PreviousSiblingElement() doesnt exist
			TiXmlNode* lNode;
			for (lNode = mCurrentFrameNode->PreviousSibling(); lNode; lNode = lNode->PreviousSibling())
				if (lNode->ToElement())
					break;//mCurrentFrameNode = lNode->ToElement;
			mCurrentFrameNode = lNode->ToElement();
			if(!mCurrentFrameNode)
				return false;
		}
	}
	else if(inFrame>mCurrentFrame)
	{
		while(conv2Num<unsigned int>(mCurrentFrameNode->Attribute("value"))!=inFrame)
		{
			mCurrentFrameNode = mCurrentFrameNode->NextSiblingElement();
			if(!mCurrentFrameNode)
				return false;	
		}
	}
	mCurrentFrame = inFrame;
	
	//Good frame
	mCurrentFrameNode->SetAttribute("value",inValue.c_str());

	if(!mXMLDocument.SaveFile())
		return false;
	//MUST KNOW THAT
	mCurrentFrameNode = mCurrentFrameNode->NextSiblingElement();
	mCurrentFrame++;

	return true;
}